package com.warren.context.annotation;

import cn.hutool.core.util.StrUtil;
import com.warren.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor;
import com.warren.beans.factory.config.BeanDefinition;
import com.warren.beans.factory.support.BeanDefinitionRegistry;

import java.lang.annotation.Annotation;
import java.util.Set;

/**
 * @author warren
 * @create 2021-08-28 22:11
 * @Description 具体扫描包处理的类
 */
public class ClassPathBeanDefinitionScanner extends ClassPathScanningCandidateComponentProvider{

    private BeanDefinitionRegistry registry;

    public ClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry){
        this.registry = registry;
    }

    /**
     * 在 doScan 中除了获取到扫描的类信息以后，
     * 还需要获取 Bean 的作用域和类名，如果不配置类名基本都是把首字母缩写
     * @param basePackages
     */
    public void doScan(String... basePackages){
        for (String basePackage : basePackages){
            Set<BeanDefinition> candidates = findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : candidates){
                //解析Bean的作用域singleton prototype
                String beanScope = resolveBeanScope(beanDefinition);
                if (StrUtil.isNotEmpty(beanScope)){
                    beanDefinition.setScope(beanScope);
                }
                registry.registerBeanDefinition(determineBeanName(beanDefinition),beanDefinition);
            }
        }
        // 注册处理注解的 BeanPostProcessor（@Autowired、@Value）
        registry.registerBeanDefinition("com.warren.context.annotation.internalAutowiredAnnotationProcessor", new BeanDefinition(AutowiredAnnotationBeanPostProcessor.class));
    }

    /**
     * 从beanDefinition中解析出scope
     * @param beanDefinition
     * @return
     */
    private String resolveBeanScope(BeanDefinition beanDefinition){
        Class<?> beanClass = beanDefinition.getBeanClass();
        Scope scope =  beanClass.getAnnotation(Scope.class);
        if (null != scope) return  scope.value();
        return StrUtil.EMPTY;
    }

    /**
     * 获取@Component注解的类的类名
     * @param beanDefinition
     * @return
     */
    private String determineBeanName(BeanDefinition beanDefinition){
        Class<?> beanClass = beanDefinition.getBeanClass();
        Component component = beanClass.getAnnotation(Component.class);
        String value = component.value();
        if (StrUtil.isEmpty(value)){
            //返回源代码中给出的基础类的简单名称
            value = StrUtil.lowerFirst(beanClass.getSimpleName());
        }
        return value;
    }
}
